/**
 *
 */
package com.bardsoftware.foronuvolo.data;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.SortedMap;

import javax.cache.Cache;
import javax.cache.CacheException;
import javax.cache.CacheManager;
import javax.jdo.PersistenceManager;
import javax.jdo.Query;

import com.google.appengine.repackaged.com.google.common.base.Pair;
import com.google.appengine.repackaged.com.google.common.collect.Lists;
import com.google.appengine.repackaged.com.google.common.collect.Maps;
import com.google.appengine.repackaged.com.google.common.collect.Sets;

public class DatastoreDiscussionChunk implements DiscussionChunk {
    private final String myID;
    private final int mySize;

    private String myPrevChunkID;
    private String myNextChunkID;
    private List<Discussion> myDiscussions;

    private DatastoreDiscussionChunk(String id) {
        myID = id;
        mySize = 10;
    }
    public DatastoreDiscussionChunk(String id, List<Discussion> discussions) {
        myDiscussions = discussions;
        myPrevChunkID = null;
        myID = id;
        myNextChunkID = null;
        mySize = discussions.size();
    }

    /* (non-Javadoc)
     * @see com.bardsoftware.foronuvolo.data.DiscussionChunk#getDiscussions()
     */
    public List<Discussion> getDiscussions() {
        if (myDiscussions == null) {
            fetchDiscussions();
        }
        return myDiscussions;
    }
    /* (non-Javadoc)
     * @see com.bardsoftware.foronuvolo.data.DiscussionChunk#getID()
     */
    public String getID() {
        return myID == null ? "" : myID;
    }

    /* (non-Javadoc)
     * @see com.bardsoftware.foronuvolo.data.DiscussionChunk#getNextChunkID()
     */
    public String getNextChunkID() {
        if (myNextChunkID == null && myDiscussions == null) {
            fetchDiscussions();
        }
        return myNextChunkID == null ? "" : myNextChunkID;
    }

    private void fetchDiscussions() {
        PersistenceManager pm = PMF.getFactory().getPersistenceManager();
        try {
            Query discussionsQuery = pm.newQuery(Discussion.class);
            discussionsQuery.setOrdering("creationOrder desc");
            discussionsQuery.setRange(0, mySize + 1);
            discussionsQuery.setFilter("creationOrder <= startRefID");
            discussionsQuery.declareParameters("String startRefID");
            myDiscussions = Lists.newArrayListWithExpectedSize(mySize + 1);
            for (Discussion d : (List<Discussion>) discussionsQuery.execute(myID == null ? Discussion.MAX_REF_ID : myID)) {
                d = pm.detachCopy(d);
                myDiscussions.add(d);
            }
            if (myDiscussions.size() == mySize + 1) {
                myNextChunkID = myDiscussions.remove(mySize).getCreationOrder();
            }
        }
        finally {
            pm.close();
        }
    }

    /* (non-Javadoc)
     * @see com.bardsoftware.foronuvolo.data.DiscussionChunk#getPrevChunkID()
     */
    public String getPrevChunkID() {
        if (myPrevChunkID == null && myID != null) {
            PersistenceManager pm = PMF.getFactory().getPersistenceManager();
            try {
                Query prevDiscussions = pm.newQuery(Discussion.class);
                prevDiscussions.setOrdering("creationOrder asc");
                prevDiscussions.setRange(0, mySize);
                prevDiscussions.setFilter("creationOrder > startRefID");
                prevDiscussions.declareParameters("String startRefID");
                List<Discussion> prevResult = (List<Discussion>) prevDiscussions.execute(myID);
                if (!prevResult.isEmpty()) {
                    assert prevResult.get(0).getCreationOrder().compareTo(myID) > 0;
                    myPrevChunkID = prevResult.get(prevResult.size() - 1).getCreationOrder();
                }
            }
            finally {
                pm.close();
            }
        }
        return myPrevChunkID == null ? "" : myPrevChunkID;
    }

    public String toString() {
        return "<chunk id="+getID()+" next="+getNextChunkID()+" size="+getDiscussions().size()+">";
    }
    public static DiscussionChunk getHotPage() {
        PersistenceManager pm = PMF.getFactory().getPersistenceManager();
        try {
            Query discussionsQuery = pm.newQuery(Message.class);
            discussionsQuery.setOrdering("myCreation desc");
            discussionsQuery.setFilter("myCreation > weekAgo");
            discussionsQuery.declareParameters("Date weekAgo");
            discussionsQuery.declareImports("import java.util.Date");
            HashMap<String,Discussion> hotDiscussions = Maps.newHashMap();
            ArrayList<Discussion> result = Lists.newArrayList();
            Calendar c = Calendar.getInstance();
            c.add(Calendar.WEEK_OF_YEAR, -1);
            for (Message m : (List<Message>) discussionsQuery.execute(c.getTime())) {
                Discussion d = pm.detachCopy(m.getDiscussion());
                if (!hotDiscussions.containsKey(d.getCreationOrder())) {
                    hotDiscussions.put(d.getCreationOrder(), d);
                    result.add(d);
                }
            }
            return new DatastoreDiscussionChunk("hot", result);
        }
        finally {
            pm.close();
        }
    }


    public static DiscussionChunk getFirstPage() {
        return getPage(null);
    }

    public static DiscussionChunk getPage(String startBookmark) {
        return new DatastoreDiscussionChunk(startBookmark);
    }

    public static boolean deleteFirstPage() {
        PersistenceManager pm = PMF.getFactory().getPersistenceManager();
        try {
            List<Discussion> discussions = DatastoreDiscussionChunk.getFirstPage().getDiscussions();
            for (Discussion d: discussions) {
                pm.deletePersistent(d);
            }
            return !DatastoreDiscussionChunk.getFirstPage().getDiscussions().isEmpty();
        }
        finally {
            pm.close();
        }
    }
    public static DiscussionChunk getInboxPage(ForumUser user) {
        // TODO Auto-generated method stub
        return null;
    }
}

